﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once

#include "GcmpModelInterface.h"
#include "IDbObject.h"
#include "GraphicsNodeId.h"
#include "IGraphicsStyleData.h"
#include "UniIdentity.h"

namespace gcmp
{
    /// \brief 图形表达的多边形偏移的方式
    ///
    /// 主要用于解决共面闪烁问题（z-fighting），此偏移只对面有效，对线无效。不会改变数据层的数据
    /// 默认情况下所有图形的面会往远离相机方向偏移一个值，为了能显示自身的边线。None模式是绝对的不偏移。
    ///
    SERIALIZABLE_ENUM_CLASS(PolygonOffsetMode)
    {
        None = 0,               ///< 不偏移    相当于custom 模式下 SetPolygonOffsetCustom(factor = 0, units = 0)
        Normal = 1,             ///< 默认的往后偏移   相当于custom 模式下 SetPolygonOffsetCustom(factor = 0.8, units = 20)
        LessThanNormal = 2,     ///< 比默认少偏移   相当于custom  模式下 SetPolygonOffsetCustom(factor = 0.5, units = 10)
        MoreThanNormal = 3,      ///< 比默认多偏移   相当于custom 模式下 SetPolygonOffsetCustom(factor = 1.1, units = 30)
        Custom = 4,              ///< 自定义  如果是自定义模式， 面偏移的值来自于SetSetPolygonOffsetCustom
    };

    /// \brief 置顶置底的参数
    ///为了以后多层置顶置底的需求， 存储的值用int表示，  -1000~1000为normal层，
    ///1000以上 up lay(Unkown为INT_MAX 除外)  -1000一下为under lay.    （值大的显示在上面， 1001在1000之上， -1000在-1001上）
    ///目前的实现不支持多层，设置的值只能是目前枚举的三个值
    enum UnderlayUplayInfo : Int32
    {
        Up_LayInfo = 2000,
        Normal_LayInfo = 0,
        Under_LayInfo = -2000,
        Unkown_LayInfo = INT_MAX,
    };

    class Vector2d;
    class IGraphicsNodeStyleAndMaterialCustomizer;
    class IElementParentReporter;
    class ICopyContext;
    class ICopyStrategyReporter;

    /// \brief 图形节点样式和材质的重载
    class GCMP_MODEL_INTERFACE_EXPORT IGraphicsNodeStyleAndMaterialOverride : public IDbObject
    {
        DEFINE_CAST_DERIVED(gcmp::IGraphicsNodeStyleAndMaterialOverride, gcmp::IDbObject)

    public:
        /// \brief 创建重载对象
        /// 
        /// \return 创建的图形节点样式和材质的重载对象
        static OwnerPtr<IGraphicsNodeStyleAndMaterialOverride> Create();

        /// \brief 重载节点上的漫反射纹理变换
        /// 
        /// 子节点不会继承父节点的漫反射纹理变换
        /// \param graphicsNodeIdPath 图形节点 id 路径，用于指定节点，路径不能为空
        /// \param offset 漫反射纹理的偏移量
        /// \param rotation 漫反射纹理的旋转量（单位：角度）
        /// \param scale 漫反射纹理的缩放量
        /// \return true-重载成功，false-重载失败
        virtual bool OverrideDiffuseTexureTransformation(const std::vector<GraphicsNodeId>& graphicsNodeIdPath, const Vector2d& offset, double rotation, const Vector2d& scale) = 0;

        /// \brief 删除节点上重载的漫反射纹理变换
        /// \param graphicsNodeIdPath 图形节点 id 路径，用于指定节点
        virtual void DeleteOverriddenDiffuseTexureTransformation(const std::vector<GraphicsNodeId>& graphicsNodeIdPath) = 0;

        /// \brief 获取节点上重载的漫反射纹理变换
        /// \param graphicsNodeIdPath 图形节点 id 路径，用于指定节点，路径不能为空
        /// \param pOffset 返回漫反射纹理的偏移量，不关心就传入 nullptr
        /// \param pRotation 返回漫反射纹理的旋转量（单位：角度），不关心就传入 nullptr
        /// \param pScale 返回漫反射纹理的缩放量，不关心就传入 nullptr
        /// \return true-获取成功，false-获取失败
        virtual bool GetOverriddenDiffuseTexureTransformation(const std::vector<GraphicsNodeId>& graphicsNodeIdPath, Vector2d* pOffset, double* pRotation, Vector2d* pScale) const = 0;
        
        /// \brief 重载图形材质
        /// 
        /// 所有节点的材质都会被重载
        /// \param materialId 图形材质的 id; 如果 id 是无效的，相当于取消重载图形材质
        virtual void OverrideGraphicsMaterial(const ElementId &materialId) = 0;

        /// \brief 获取重载的图形材质
        /// \return 重载用的图形材质的 id
        virtual ElementId GetOverriddenGraphicsMaterial() const = 0;

        /// \brief 重载图形样式
        /// 
        /// 所有节点的样式都会被重载，如果设置图形样式定制器后，该设置的值将不起作用
        /// \param styleId 图形样式的 id; 如果 id 是无效的，相当于取消重载图形样式
        virtual void OverrideGraphicsStyle(const ElementId &styleId) = 0;

        /// \brief 获取重载的图形样式
        /// \return 重载用的图形样式的 id
        virtual ElementId GetOverriddenGraphicsStyle() const = 0;

        /// \brief 设置图形样式定制器
        /// 
        /// 所有节点的样式都会被重载，设置的定制器不为空后通过重载图形样式接口（OverrideGraphicsStyle）将不起作用
        /// \param opCustomizer 图形样式定制器; 如果图形样式定制器为空，相当于取消图形样式定制
        virtual bool SetGraphicsNodeStyleAndMaterialCustomizer(OwnerPtr<IGraphicsNodeStyleAndMaterialCustomizer> opCustomizer) = 0;

        /// \brief 获取图形样式定制器
        /// \return 图形样式定制器对象
        virtual const IGraphicsNodeStyleAndMaterialCustomizer* GetGraphicsNodeStyleAndMaterialCustomizer() const = 0;

        /// \brief 批量处理图形节点上的标签重载图形样式
        ///
        /// 废弃!!!最好不要再新使用了!!!
        /// \param tag 图形节点上的标签
        /// \param styleId 重载图形样式的 id; 如果 id 是无效的，相当于取消图形样式的重载
        GCMP_DEPRECATED_API(2022 / 12 / 30) virtual void OverrideGraphicsStyleByGraphicsNodeTag(const Guid &tag, const ElementId &styleId) = 0;

        /// \brief 获取所有通过Tag重载style的map
        /// 废弃!!!最好不要再新使用了!!!
        /// \return 通过Tag重载的style的map
        GCMP_DEPRECATED_API(2022 / 12 / 30) virtual const std::map<Guid, ElementId, GuidComparer>& GetOverriddenGraphicsStylesByGraphicsNodeTag() const = 0;

        /// \brief 通过节点上的样式对应名称重载图形样式
        ///
        /// \param name 节点上样式的名称
        /// \param styleId 重载图形样式的 id; 如果 id 是无效的，相当于取消图形样式的重载
        virtual void OverrideGraphicsStyleByStyleName(const std::wstring &name, const ElementId &styleId) const = 0;

        /// \brief 通过节点上的样式对应名称重载图形样式
        ///
        /// \return std::map<std::wstring, ElementId>  返回通过构件上graphic node的样式样式名重载的新样式的映射关系表
        virtual const std::map<std::wstring, ElementId>& GetOverriddenGraphicsStylesByStyleName() const = 0;

        /// \brief 通过节点上样式对应类别guid重载图形样式
        ///
        /// \param name 节点上样式的类别guid
        /// \param styleId 重载图形样式的 id; 如果 id 是无效的，相当于取消图形样式的重载
        virtual void OverrideGraphicsStyleByCategoryUid(const gcmp::UniIdentity &categoryUid, const ElementId &styleId) const = 0;

        /// \brief 通过节点上的样式对应类别guid重载图形样式
        ///
        /// \return std::map<gcmp::UniIdentity, ElementId>  返回通过构件上graphic node的样式TargetCategoryUid重载的新样式的映射关系表
        virtual const std::map<gcmp::UniIdentity, ElementId>& GetOverriddenGraphicsStylesByCategoryUid() const = 0;

        /// \brief 通过节点上的材质对应名称重载图形材质
        ///
        /// \param name 节点上材质的名称
        /// \param materialId 重载图形材质的 id; 如果 id 是无效的，相当于取消图形材质的重载
        virtual void OverrideGraphicsMaterialByMaterialName(const std::wstring &name, const ElementId &materialId) const = 0;

        /// \brief 获取通过节点上的材质对应名称重载图形材质映射表
        ///
        /// \return std::map<std::wstring, ElementId>  返回通过构件上graphic node的材质名materialName重载的新材质的映射关系表
        virtual const std::map<std::wstring, ElementId>& GetOverriddenGraphicsMaterialsByMaterialName() const = 0;

        /// \brief 通过节点上材质对应类别guid重载图形材质
        ///
        /// \param name 节点上材质的类别guid
        /// \param materialId 重载图形材质的 id; 如果 id 是无效的，相当于取消图形材质的重载
        virtual void OverrideGraphicsMaterialByTargetCategoryUid(const gcmp::UniIdentity &targetCategoryUid, const ElementId &materialId) const = 0;

        /// \brief 获取通过节点上的材质对应类别guid重载图形材质映射表
        ///
        /// \return std::map<gcmp::UniIdentity, ElementId>  返回通过构件上graphic node的tarGetCategoryUid重载的新材质的映射关系表
        virtual const std::map<gcmp::UniIdentity, ElementId>& GetOverriddenGraphicsMaterialsByTargetCategoryUid() const = 0;

        /// \brief 设置图形节点的多边形面偏移
        /// 
        /// 只对面有效，线无法偏移
        /// \param offset 面的偏移方式
        virtual void SetPolygonOffsetMode(PolygonOffsetMode offset) = 0;

        /// \brief 得到图形节点上的多边形面偏移
        /// \return 面的偏移方式
        virtual PolygonOffsetMode GetPolygonOffsetMode() const = 0;

        /// \brief PolygonOffsetMode为Custom时， 此接口设置的值有效
        ///
        ///设置面偏移自定义的值， 最终调用的是glPolygonOffset
        ///当值大于0时， 会让物体远离相机， 反之则会靠近相机        
        ///详情见https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glPolygonOffset.xhtml
        ///另外， 由于ggp对外的接口， units是浮点数而不是unsigned，同它保持一致
        virtual void SetPolygonOffsetCustom(float factor, float units) = 0; 

        /// \brief 得到图形节点上的多边形面偏移
        /// \return  获取面偏移设置的factor和units属性
        virtual void GetPolygonOffsetCustom(float &factor, float &units) const = 0;
        
        /// \brief 设置图形节点是否支持线框模式显示
        /// 
        /// 线框模式下， Face将被过滤并不在显示
        /// 不支持线框模式下和Solid模式现象保持一致
        /// \param enable 是否支持线框模式
        ///
        /// \return void
        virtual void EnableWireFrameMode(bool enable) = 0;
        
        /// \brief 获取图形节点是否支持线框模式显示, ，默认为true
        /// \return true-支持线框模式显示， false-不支持线框模式显示
        virtual bool IsWireFrameModeEnabled() const = 0;

        /// \brief 设置图形节点是否支持消隐线模式显示
        /// 
        /// 不支持消隐线模式和Solid模式现象保持一致
        /// \param enable 是否支持消隐线模式
        /// \return void
        virtual void EnableHiddenLineMode(bool enable) = 0;

        /// \brief 获取图形节点是否支持消隐线模式显示, ，默认为true
        /// \return true-支持消隐线模式显示， false-不支持消隐线模式显示
        virtual bool IsHiddenLineModeEnabled() const = 0;


        /// \brief 设置行为所属Element
        /// \param pOwnerElement 所属Element
        /// \return bool
        virtual bool SetOwnerElement(IElement* pOwnerElement) = 0;

        /// \brief 获得行为所属的Element
        /// \return 所属的Element
        virtual IElement* GetOwnerElement() = 0;

        /// \brief 获得行为所属的Element
        /// \return 所属的Element
        virtual const IElement* GetOwnerElement() const = 0;

        /// \brief 获得行为所属的Element所在的文档
        /// \return 所属的文档
        virtual IDocument* GetDocument() const = 0;

        /// \brief 获取图元合并分组id
        /// \return 返回图元合并分组id，默认为0
        virtual UInt16 GetRenderPatchCombineId() const = 0;

        /// \brief 设置element所属图元合并分组id
        /// \param id,所属图元合并分组id
        virtual void SetRenderPatchCombineId(const UInt16& id) = 0;

        /// \brief 设置所属 Element 的置顶置底信息（文档级，优先级低于视图级）
        ///
        /// \param info                  置顶置底信息(目前只能支持 UnderlayUplayInfo 所列举的枚举)
        /// \ 枚举类型
        /// \       Up_LayInfo = 2000,
        /// \       Normal_LayInfo = 0,
        /// \       Under_LayInfo = -2000,
        /// \       Unkown_LayInfo = INT_MAX,
        /// \return void
        virtual void AddElementUnderLayUpLayInfo(int info) const = 0;

        /// \brief 移除所属 Element 的置顶置底信息（文档级，优先级低于视图级）
        ///
        /// \return void
        virtual void RemoveElementUnderLayUpLayInfo() const = 0;

        /// \brief 获取所属 Element 的置顶置底信息（文档级，优先级低于视图级）
        ///   目前只能支持 UnderlayUplayInfo 所列举的枚举
        /// \ 枚举类型
        /// \       Up_LayInfo = 2000,
        /// \       Normal_LayInfo = 0,
        /// \       Under_LayInfo = -2000,
        /// \       Unkown_LayInfo = INT_MAX,
        /// \return UnderlayUplayInfo  置顶置底信息的枚举值
        virtual int GetElementUnderLayUpLayInfo() const = 0;

        /// \brief 当弱依赖的Element被删除后，此接口会被调用。
        /// \param deleteElementIds 表示将被删除的Element ids
        /// \return void
        virtual void UpdateForWeakParentDeletion(const std::set<ElementId>& deletedElementIds) = 0;

        /// \brief 报告依赖的ElementIds。对象删除和关联更新依赖于这个接口的正确实现。
        /// \param reporter 报告接口
        /// \return void
        virtual void ReportParents(IElementParentReporter& reporter) const = 0;

        /// \brief 报告引用的Element的id为拷贝、保持、放弃
        /// \param copyContext 拷贝上下文
        /// \param reporter 拷贝策略报告器
        /// \return void
        /// \see ICopyStrategyReporter
        virtual void ReportCopyStrategry(const gcmp::ICopyContext& copyContext, gcmp::ICopyStrategyReporter& reporter) const = 0;

        /// \brief 获取所有图形节点上的纹理变换信息
        /// \return 图形节点路径及对应纹理变换信息(offset/rotation/scale)
        virtual std::map<std::vector<GraphicsNodeId>, std::tuple<Vector2d, double, Vector2d> > GetAllTextureTransformations() const = 0;
    };
}
